home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-07-02 | 7.9 KB | 402 lines | [TEXT/MPCC] |
- /*
- ** CTelnetInterp.cp
- **
- ** TurboTCP support library
- ** Generic Telnet protocol interpreter
- **
- ** Copyright © 1993-94, FrostByte Design / Eric Scouten
- **
- */
-
-
- #include "CTelnetInterp.h"
-
- TCL_DEFINE_CLASS_M1(CTelnetInterp, CTCPEndpoint);
-
-
- // —— constructor ——
-
- /*______________________________________________________________________
- **
- ** constructor
- **
- ** Initialize the Telnet interpreter.
- **
- ** theDefaultPort (unsigned short): default IP port number (the only required parameter)
- ** recBufferSize (unsigned long): size of receive buffer to create
- ** autoReceiveSize (unsigned short): number of entries in RDS for auto-receive,
- ** 0 to disable autoreceiving
- ** autoReceiveNum (unsigned short): number of auto-receive calls to issue at once
- ** must be at least 1
- ** doUseCName (Boolean): TRUE to get canonical name of remote host
- ** whenever possible
- **
- */
-
- CTelnetInterp::CTelnetInterp(unsigned short theDefaultPort, unsigned long recBufferSize,
- unsigned short autoReceiveSize, unsigned short autoReceiveNum,
- Boolean doUseCName)
-
- : CTCPEndpoint(theDefaultPort, recBufferSize, autoReceiveSize, autoReceiveNum, doUseCName)
-
- {
- itsState = normalChar;
- showFileName = FALSE;
- }
-
-
- // —— Telnet command handling ——
-
- // If you wish to respond to specific Telnet commands, override these methods.
- // You may ignore any or all of these methods.
-
- /*______________________________________________________________________
- **
- ** ReceivedWill
- **
- ** Respond to a Telnet [IAC WILL option] sequence. Default method responds [WONT option].
- ** Override to implement any Telnet options, call this method to reject any unimplemented
- ** options.
- **
- ** theOption (uchar): the option code
- **
- */
-
- void CTelnetInterp::ReceivedWill(uchar theOption)
-
- {
- char respondStr[4];
-
-
- // reject all options
-
- respondStr[0] = charIAC;
- respondStr[1] = escWONT;
- respondStr[2] = theOption;
- respondStr[3] = '\0';
- if (showDebug) {
- PrintDebugStr("{IAC WONT");
- PrintDebugCharNum(theOption, ' ', '}');
- }
- *this << respondStr;
- }
-
-
- /*______________________________________________________________________
- **
- ** ReceivedDo
- **
- ** Respond to a Telnet [IAC DO option] sequence. Default method responds [WONT option].
- ** Override to implement any Telnet options, call this method to reject any unimplemented
- ** options.
- **
- ** theOption (uchar): the option code
- **
- */
-
- void CTelnetInterp::ReceivedDo(uchar theOption)
-
- {
- char respondStr[4];
-
-
- // reject all options
-
- respondStr[0] = charIAC;
- respondStr[1] = escWONT;
- respondStr[2] = theOption;
- respondStr[3] = '\0';
- if (showDebug) {
- PrintDebugStr("{IAC WONT");
- PrintDebugCharNum(theOption, ' ', '}');
- }
- *this << respondStr;
- }
-
-
- /*______________________________________________________________________
- **
- ** ReceivedSB
- **
- ** Receive subnegotiation parameters. Buffers characters until SE is received.
- **
- ** theChar (uchar): the latest character
- **
- */
-
- void CTelnetInterp::ReceivedSB(uchar theChar)
-
- {
- if (showDebug)
- PrintDebugCharNum(theChar, ' ', '\0');
- sbBfr[sbBfrIndex++] = theChar;
- }
-
-
- // —— respond to incoming data (do not override) ——
-
- /*______________________________________________________________________
- **
- ** HandleDataArrived (private method)
- **
- ** Process incoming data.
- **
- ** theData (void*): pointer to the block of data
- ** theDataSize (unsigned short): size of the data block
- ** isUrgent (Boolean): TRUE if urgent data
- **
- */
-
- void CTelnetInterp::HandleDataArrived(void* theData, unsigned short theDataSize, Boolean isUrgent)
-
- {
- char* xData = (char*) theData; // hack to avoid lots of typecasts
- uchar theChar;
- char theLine[83];
- short lineIndex;
-
-
- // parse each character separately
-
- while (theDataSize--) {
- theChar = (uchar) (*(xData++));
-
-
- // respond to current Telnet state
-
- switch (itsState) {
-
-
- // normal operation: write character
-
- case normalChar:
-
-
- // optimization: try to grab several chars at once
-
- lineIndex = 0;
- while ((theDataSize > 1) && (theChar >= ' ') && (theChar != charIAC)) {
- theDataSize++;
- xData--;
- lineIndex = 0;
- while ((theDataSize > 0) && (((uchar) *xData) >= ' ') &&
- (*xData != charIAC) && (lineIndex < 80))
- theDataSize--, theLine[lineIndex++] = (uchar) *(xData++);
- if ((theDataSize > 0) && (*xData == charCR))
- theDataSize--, xData++, theLine[lineIndex++] = charCR;
- if ((theDataSize > 0) && (*xData == charLF))
- theDataSize--, xData++, theLine[lineIndex++] = charLF;
- theLine[lineIndex] = '\0';
- if (lineIndex)
- HandleNVTLine((char*) &theLine[0]);
- if (theDataSize < 1)
- break;
- theChar = (uchar) (*(xData++));
- theDataSize--;
- }
-
- if ((lineIndex) && !(theDataSize))
- break;
-
-
- // end of loop: test for IAC
-
- if (theChar == charIAC) {
- itsState = gotIAC;
- if (showDebug)
- PrintDebugStr("[IAC");
- }
- else
- HandleNVTChar(theChar);
- break;
-
-
- // received IAC (interpret as command)
-
- case gotIAC:
- case gotIACinSB:
- ReceivedIAC(theChar);
- break;
-
-
- // handle other cases
-
- case gotSB:
- if (theChar == charIAC) {
- itsState = gotIACinSB;
- if (showDebug)
- PrintDebugStr(" IAC");
- }
- else
- ReceivedSB(theChar);
- break;
-
- case gotWILL:
- if (showDebug)
- PrintDebugCharNum(theChar, ' ', ']');
- ReceivedWill(theChar);
- itsState = normalChar;
- break;
-
- case gotWONT:
- if (showDebug)
- PrintDebugCharNum(theChar, ' ', ']');
- ReceivedWont(theChar);
- itsState = normalChar;
- break;
-
- case gotDO:
- if (showDebug)
- PrintDebugCharNum(theChar, ' ', ']');
- ReceivedDo(theChar);
- itsState = normalChar;
- break;
-
- case gotDONT:
- if (showDebug)
- PrintDebugCharNum(theChar, ' ', ']');
- ReceivedDont(theChar);
- itsState = normalChar;
- break;
- }
- }
-
- }
-
-
- /*______________________________________________________________________
- **
- ** ReceivedIAC
- **
- ** Respond to a Telnet [IAC command] sequence.
- **
- ** theCommand (uchar): the command code
- **
- */
-
- void CTelnetInterp::ReceivedIAC(uchar theCommand)
-
- {
-
- // which command is it?
-
- switch (theCommand) {
-
- case escSE:
- if (showDebug)
- PrintDebugStr(" SE]");
- sbBfr[sbBfrIndex] = '\0';
- if (itsState == gotIACinSB)
- ReceivedSE();
- itsState = normalChar;
- break;
-
- case escNOP:
- if (showDebug)
- PrintDebugStr(" NOP]");
- itsState = normalChar;
- break;
-
- case escDM:
- if (showDebug)
- PrintDebugStr(" DM]");
- ReceivedSynch();
- itsState = normalChar;
- break;
-
- case escBRK:
- if (showDebug)
- PrintDebugStr(" BRK]");
- ReceivedBRK();
- itsState = normalChar;
- break;
-
- case escIP:
- if (showDebug)
- PrintDebugStr(" IP]");
- ReceivedIP();
- itsState = normalChar;
- break;
-
- case escAO:
- if (showDebug)
- PrintDebugStr(" AO]");
- ReceivedAO();
- itsState = normalChar;
- break;
-
- case escAYT:
- if (showDebug)
- PrintDebugStr(" AYT]");
- ReceivedAYT();
- itsState = normalChar;
- break;
-
- case escEC:
- if (showDebug)
- PrintDebugStr(" EC]");
- ReceivedEC();
- itsState = normalChar;
- break;
-
- case escEL:
- if (showDebug)
- PrintDebugStr(" EL]");
- ReceivedEL();
- itsState = normalChar;
- break;
-
- case escGA:
- if (showDebug)
- PrintDebugStr(" GA]");
- ReceivedGA();
- itsState = normalChar;
- break;
-
- case escSB:
- if (showDebug)
- PrintDebugStr(" SB");
- itsState = gotSB;
- sbBfrIndex = 0;
- break;
-
- case escWILL:
- if (showDebug)
- PrintDebugStr(" WILL");
- itsState = gotWILL;
- break;
-
- case escWONT:
- if (showDebug)
- PrintDebugStr(" WONT");
- itsState = gotWONT;
- break;
-
- case escDO:
- if (showDebug)
- PrintDebugStr(" DO");
- itsState = gotDO;
- break;
-
- case escDONT:
- if (showDebug)
- PrintDebugStr(" DONT");
- itsState = gotDONT;
- break;
-
- case escIAC:
- default:
- if (itsState == gotIACinSB) {
- ReceivedSB(theCommand);
- itsState = gotIAC;
- }
- else {
- if (showDebug)
- PrintDebugCharNum(theCommand, '?', ']');
- HandleNVTChar(theCommand);
- itsState = normalChar;
- }
- }
-
- }
-